package middleware

import (
	"context"
	"fmt"
	"github.com/go-chi/chi/v5"
	"github.com/go-chi/render"
	pgdb "gsc-datasets/internal/db/sqlc"
	"gsc-datasets/internal/rest/constants"
	appRender "gsc-datasets/internal/rest/render"
	"gsc-datasets/internal/rest/routers"
	"gsc-datasets/pkg/util"
	"net/http"
	"strconv"
)

func WithDataset(rr *routers.RestRouter, datasetKey util.ContextKey) func(http.Handler) http.Handler {
	logger := rr.Logger("WithDataset")
	return func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			datasetVal := chi.URLParam(r, string(datasetKey))
			if util.IsEmpty(datasetVal) {
				render.Render(w, r, appRender.ErrBadRequest(fmt.Errorf("%s is empty", datasetKey)))
				return
			}
			// 检查user_id和dataset_id是否匹配,后续考虑改为cache获取
			ctx := r.Context()
			var datasetPtr *pgdb.Dataset
			if util.StartWith(datasetVal, "qtd") && len(datasetVal) == 32 {
				dataset, err := rr.Dao().GetDatasetByCode(ctx, datasetVal)
				if err != nil {
					render.Render(w, r, appRender.ErrRender(err))
					return
				}
				datasetPtr = &dataset
			} else {
				datasetID, err := strconv.ParseInt(datasetVal, 10, 64)
				if err != nil {
					render.Render(w, r, appRender.ErrBadRequest(fmt.Errorf("%s is invalid", datasetKey)))
					return
				}
				logger.Infof("dataset_id=>%d", datasetID)
				dataset, err := rr.Dao().GetDataset(ctx, datasetID)
				if err != nil {
					render.Render(w, r, appRender.ErrRender(err))
					return
				}
				datasetPtr = &dataset
			}
			userPtr := ctx.Value(constants.UserKey).(*pgdb.User)
			if datasetPtr.UserID != userPtr.ID {
				render.Render(w, r, appRender.ErrNotAuthorized(fmt.Errorf("user_id invalid")))
				return
			}
			ctx = context.WithValue(ctx, datasetKey, datasetPtr)
			next.ServeHTTP(w, r.WithContext(ctx))
		})
	}
}

func WithDatasetEntry(rr *routers.RestRouter, datasetEntryKey util.ContextKey) func(http.Handler) http.Handler {
	logger := rr.Logger("WithDatasetEntry")
	return func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			_datasetEntryID := chi.URLParam(r, string(datasetEntryKey))
			if util.IsEmpty(_datasetEntryID) {
				render.Render(w, r, appRender.ErrBadRequest(fmt.Errorf("%s is empty", datasetEntryKey)))
				return
			}
			datasetEntryID, err := strconv.ParseInt(_datasetEntryID, 10, 64)
			if err != nil {
				render.Render(w, r, appRender.ErrBadRequest(fmt.Errorf("%s is invalid", datasetEntryKey)))
				return
			}
			logger.Infof("dataset_entry_id=>%d", datasetEntryID)
			ctx := r.Context()
			datasetEntry, err := rr.Dao().GetDatasetEntry(ctx, datasetEntryID)
			if err != nil {
				render.Render(w, r, appRender.ErrRender(err))
				return
			}
			ctx = context.WithValue(ctx, datasetEntryKey, &datasetEntry)
			next.ServeHTTP(w, r.WithContext(ctx))
		})
	}
}

func WithDatasetAnnotation(rr *routers.RestRouter, datasetAnnotationKey util.ContextKey) func(http.Handler) http.Handler {
	logger := rr.Logger("WithDatasetAnnotation")
	return func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			_datasetAnnotationID := chi.URLParam(r, string(datasetAnnotationKey))
			if util.IsEmpty(_datasetAnnotationID) {
				render.Render(w, r, appRender.ErrBadRequest(fmt.Errorf("%s is empty", datasetAnnotationKey)))
				return
			}
			datasetAnnotationID, err := strconv.ParseInt(_datasetAnnotationID, 10, 64)
			if err != nil {
				render.Render(w, r, appRender.ErrBadRequest(fmt.Errorf("%s is invalid", datasetAnnotationKey)))
				return
			}
			logger.Infof("dataset_annotation_id=>%d", datasetAnnotationID)
			ctx := r.Context()
			datasetAnnotation, err := rr.Dao().GetDatasetAnnotataion(ctx, datasetAnnotationID)
			if err != nil {
				render.Render(w, r, appRender.ErrRender(err))
				return
			}
			ctx = context.WithValue(ctx, datasetAnnotationKey, &datasetAnnotation)
			next.ServeHTTP(w, r.WithContext(ctx))
		})
	}
}

func WithCategoryID(rr *routers.RestRouter, categoryIDKey util.ContextKey) func(http.Handler) http.Handler {
	logger := rr.Logger("WithCategoryID")
	return func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			_categoryID := chi.URLParam(r, string(categoryIDKey))
			if util.IsEmpty(_categoryID) {
				render.Render(w, r, appRender.ErrBadRequest(fmt.Errorf("%s is empty", categoryIDKey)))
				return
			}
			categoryID, err := strconv.ParseInt(_categoryID, 10, 64)
			if err != nil {
				render.Render(w, r, appRender.ErrBadRequest(fmt.Errorf("%s is invalid", categoryIDKey)))
				return
			}
			logger.Infof("category_id=>%d", categoryID)
			ctx := context.WithValue(r.Context(), categoryIDKey, categoryID)
			next.ServeHTTP(w, r.WithContext(ctx))
		})
	}
}
